/*
* Sun Public License Notice
*
* The contents of this file are subject to the Sun Public License
* Version 1.0 (the "License"). You may not use this file except in
* compliance with the License. A copy of the License is available at
* http://www.sun.com/
*
* The Original Code is Forte for Java, Community Edition. The Initial
* Developer of the Original Code is Sun Microsystems, Inc. Portions
* Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved.
*/
package org.netbeans.editor;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
/**
* Support class for chain of MarkBlocks
*
* @author Miloslav Metelka
* @version 1.00
*/
public class MarkChain {
/** Chain of all marks */
protected MarkFactory.ChainDrawMark chain;
/** Current mark to make checks faster */
protected MarkFactory.ChainDrawMark curMark;
/** Document for this mark */
protected BaseDocument doc;
/** If this chain uses draw marks, then this is the name for the draw layer
* that will be used for the marks
*/
protected String layerName;
/** Construct chain using draw marks */
public MarkChain(BaseDocument doc, String layerName) {
this.doc = doc;
this.layerName = layerName;
}
public final MarkFactory.ChainDrawMark getChain() {
return chain;
}
public final MarkFactory.ChainDrawMark getCurMark() {
return curMark;
}
/** Tests whether the position range is partly or fully inside
* some mark block from the chain.
* @param pos compared position
* @return relation of curMark to the given position
*/
public int compareMark(int pos) {
try {
if (curMark == null) {
curMark = chain;
if (curMark == null) {
return -1; // no marks yet
}
}
int rel;
boolean after = false;
boolean before = false;
while ((rel = curMark.compare(pos)) != 0) { // just match
if (rel > 0) { // this mark after pos
if (before) {
return rel;
}
if (curMark.prev != null) {
after = true;
curMark = curMark.prev;
} else { // end of chain
return rel;
}
} else { // this mark before pos
if (after) {
return rel;
}
if (curMark.next != null) {
before = true;
curMark = curMark.next;
} else { // start of chain
return rel;
}
}
}
return 0; // match
} catch (InvalidMarkException e) {
if (Boolean.getBoolean("netbeans.debug.exceptions")) { // NOI18N
e.printStackTrace();
}
return -1; // don't match, but what to return?
}
}
protected MarkFactory.ChainDrawMark createAndInsertNewMark(int pos)
throws BadLocationException {
MarkFactory.ChainDrawMark mark = createMark();
try {
doc.op.insertMark(mark, pos);
} catch (InvalidMarkException e) {
if (Boolean.getBoolean("netbeans.debug.exceptions")) { // NOI18N
e.printStackTrace();
}
}
return mark;
}
protected MarkFactory.ChainDrawMark createMark() {
MarkFactory.ChainDrawMark mark = new MarkFactory.ChainDrawMark(layerName, null);
mark.insertAfter = true; // stay at line begining
mark.activateLayer = true;
return mark;
}
/** Add mark to the chain
* @return true if the mark was added
* false if there's already mark at that pos
*/
public boolean addMark(int pos) throws BadLocationException {
int rel = compareMark(pos);
if (rel == 0) {
return false; // already exists
} else if (rel > 0) { // curMark after pos
MarkFactory.ChainDrawMark mark = createAndInsertNewMark(pos);
if (curMark != null) {
if (curMark == chain) { // curMark is first mark
chain = curMark.insertChain(mark);
} else { // curMark is not first mark
curMark.insertChain(mark);
}
} else { // no marks in chain
chain = mark;
}
} else { // curMark before pos
MarkFactory.ChainDrawMark mark = createAndInsertNewMark(pos);
if (curMark != null) {
if (curMark.next != null) {
curMark.next.insertChain(mark);
} else { // last mark in chain
curMark.setNextChain(mark);
}
} else { // no marks in chain
chain = mark;
}
}
return true;
}
/** Remove non-empty block from area covered by blocks from chain */
public boolean removeMark(int pos) {
int rel = compareMark(pos);
if (rel == 0) {
boolean first = (curMark == chain);
curMark = curMark.removeChain();
if (first) {
chain = curMark;
}
return true;
} else { // not found
return false;
}
}
/** Is there mark at given position? */
public boolean isMark(int pos) {
return (compareMark(pos) == 0);
}
/** Toggle the mark so that if it didn't exist it is created
* and if it existed it's removed
* @return true if the new mark was added
* false if the existing mark was removed
*/
public boolean toggleMark(int pos) throws BadLocationException {
int rel = compareMark(pos);
if (rel == 0) { // exists
removeMark(pos);
return false;
} else { // didn't exist
addMark(pos);
return true;
}
}
public String toString() {
return "MarkChain: curMark=" + curMark + ", mark chain: " // NOI18N
+ (chain != null ? ("\n" + chain.toStringChain()) : "Empty"); // NOI18N
}
}
/*
* Log
* 10 Gandalf-post-FCS1.8.1.0 3/8/00 Miloslav Metelka
* 9 Gandalf 1.8 1/13/00 Miloslav Metelka
* 8 Gandalf 1.7 1/10/00 Miloslav Metelka
* 7 Gandalf 1.6 11/14/99 Miloslav Metelka
* 6 Gandalf 1.5 11/8/99 Miloslav Metelka
* 5 Gandalf 1.4 10/23/99 Ian Formanek NO SEMANTIC CHANGE - Sun
* Microsystems Copyright in File Comment
* 4 Gandalf 1.3 10/10/99 Miloslav Metelka
* 3 Gandalf 1.2 3/23/99 Miloslav Metelka
* 2 Gandalf 1.1 3/18/99 Miloslav Metelka
* 1 Gandalf 1.0 3/18/99 Miloslav Metelka
* $
*/